/*
	The Shadow Framework - a complete framework for Real Time Graphics based on OpenGL
    Copyright (C) 2008  Alessandro Martinelli  <alessandro.martinelli@unipv.it>

    This file is part of The Shadow Framework.

    The Shadow Framework is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    The Shadow Framework is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Shadow Framework.  If not, see <http://www.gnu.org/licenses/>.
*/

package objLoader.math;

public class Quaternion {

	public float x,y,z,w;
	
	public Quaternion(){}
	
	public Quaternion(Quaternion q){
		x=q.x;
		y=q.y;
		z=q.z;
		w=q.w;
	}
	
	public void normalize(){
		float rlength=1.0f/(float)(Math.sqrt(x*x+y*y+z*z+w*w));
		x*=rlength;
		y*=rlength;
		z*=rlength;
	}
	
	public void addTo(Quaternion q){
		x+=q.x;
		y+=q.y;
		z+=q.z;
		w+=q.w;
	}
	
	public void subtractTo(Quaternion q){
		x-=q.x;
		y-=q.y;
		z-=q.z;
		w-=q.w;
	}

	public void set(Quaternion q){
		x=q.x;
		y=q.y;
		z=q.z;
		w=q.w;
	}
	
	public void multTo(float q){
		x*=q;
		y*=q;
		z*=q;
		w*=q;
	}
	
	public void multTo(Quaternion q){
		float w1=w*q.w-x*q.x-y*q.y-z*q.z;
		float x1=w*q.x+x*q.w+z*q.y-y*q.z;
		float y1=w*q.y+y*q.w+x*q.z-z*q.x;
		float z1=w*q.z+z*q.w+y*q.x-x*q.y;
		this.x=x1;
		this.y=y1;
		this.z=z1;
		this.w=w1;
	}
	
	public Quaternion add(Quaternion q){
		Quaternion d=new Quaternion(this);
		d.addTo(q);
		return d;
	}
	
	public Quaternion subtract(Quaternion q){
		Quaternion d=new Quaternion(this);
		d.subtractTo(q);
		return d;
	}
	
	public Quaternion mult(float q){
		Quaternion d=new Quaternion(this);
		d.multTo(q);
		return d;
	}
	
	public Quaternion mult(Quaternion q){
		Quaternion d=new Quaternion(this);
		d.multTo(q);
		return d;
	}
	
	public Vertex3f applayRotation(Vertex3f a){
		Vertex3f b=new Vertex3f(a.x,a.y,a.z);
		
		float x1=(float)(y*a.z-z*a.y);
		float y1=(float)(z*a.x-x*a.z);
		float z1=(float)(x*a.y-y*a.x);
		
		float x2=y*z1-z*y1;
		float y2=z*x1-x*z1;
		float z2=x*y1-y*x1;
		
		float wr=1-w;
		
		b.x+=x1+wr*x2;
		b.y+=y1+wr*y2;
		b.z+=z1+wr*z2;
		
		return b;
	}
	
	public Matrix getRotationMatrix(){
		Matrix m=new Matrix();
		
		m.setA(1 - 2*(y*y + z*z));   //L'ultimo termine.. y( x ay - y ax ) - z*( z ax - x az )  = (-y*y -z*z)ax  +x*y ay + z*x az 
		m.setB(-2*z*w+2*x*y);
		m.setC(2*w*y +2*x*z);

		m.setD(2*z*w+2*x*y);
		m.setE(1 - 2*(x*x + z*z));
		m.setF(2*y*z-2*x*w);

		m.setG(2*x*z-2*w*y);
		m.setH(2*y*y-2*w*x);
		m.setI(1 - 2*(x*x + y*y));
		
		return m;
	}

}
